/*
 * Copyright (c) 2012, Dennis Lee & Christopher Uyeda
 * All rights reserved.
 * 
 * Redistribution and use in source and binary forms, with or without modification
 * are permitted provided that the following conditions are met:
 * 		* Redistributions of source code must retain the above copyright notice,
 * 		  this list of conditions and the following disclaimer.
 * 		* Redistributions in binary form must reproduce the above copyright notice,
 * 		  this list of conditions and the following disclaimer in the documentation
 * 		  and/or other materials provided with the distribution.
 *		* Neither the name of the University of Hawaii at Manoa or the names of
 * 		  its contributors may be used to endorse or promote products derived from
 *		  this software without specific prior written permission.
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
 * OF THE POSSIBILITY OF SUCH DAMAGE.
 */
package quickstats;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.TreeSet;

/**
 * MonovariateCalculator
 *
 * @author Dennis Lee & Christopher Uyeda
 * @date November 29th 2012
 * @abstract Computes descriptive statistics and inferential statistics
 * (monovariate analysis & bivariate analysis) on two given double arrays
 */
public class BivariateCalculator {

    /* samples */
    protected double[] sampleOne;
    protected double[] sampleTwo;
    /* descriptive statistics of sample one */
    protected int sampleOne_samplesize;
    protected double sampleOne_sum;
    protected double sampleOne_mean;
    protected double sampleOne_median;
    protected String sampleOne_mode;
    protected double sampleOne_max;
    protected double sampleOne_min;
    protected double sampleOne_range;
    protected double sampleOne_geometricmean;
    protected double sampleOne_skewness;
    protected double sampleOne_kurtosis;
    protected double sampleOne_excesskurtosis;
    protected double sampleOne_variance;
    protected double sampleOne_stddev;
    protected double sampleOne_firstquartile;
    protected double sampleOne_secondquartile;
    protected double sampleOne_thirdquartile;
    protected double sampleOne_fourthquartile;
    protected double sampleOne_firstinterquartilerange;
    protected double sampleOne_secondinterquartilerange;
    protected double sampleOne_thirdinterquartilerange;
    protected double sampleOne_fourthinterquartilerange;
    protected String sampleOne_frequencydist;
    /* descriptive statistics of sample two */
    protected int sampleTwo_samplesize;
    protected double sampleTwo_sum;
    protected double sampleTwo_mean;
    protected double sampleTwo_median;
    protected String sampleTwo_mode;
    protected double sampleTwo_max;
    protected double sampleTwo_min;
    protected double sampleTwo_range;
    protected double sampleTwo_geometricmean;
    protected double sampleTwo_skewness;
    protected double sampleTwo_kurtosis;
    protected double sampleTwo_excesskurtosis;
    protected double sampleTwo_variance;
    protected double sampleTwo_stddev;
    protected double sampleTwo_firstquartile;
    protected double sampleTwo_secondquartile;
    protected double sampleTwo_thirdquartile;
    protected double sampleTwo_fourthquartile;
    protected double sampleTwo_firstinterquartilerange;
    protected double sampleTwo_secondinterquartilerange;
    protected double sampleTwo_thirdinterquartilerange;
    protected double sampleTwo_fourthinterquartilerange;
    protected String sampleTwo_frequencydist;
    /*inferential statistics */
    protected double pearsoncorrelation;
    protected double ttest;
    /* flags */
    protected boolean loaded;
    protected boolean computed;
    
    /*
     * arrays used to hold frequency distribution values
     * only used for JUnit test cases
     */
    protected ArrayList<Integer> freqCount;
    protected int[] freqCount2;
    protected ArrayList<Integer> freqCount3;
    protected int[] freqCount4;

    /*
     * constructor
     */
    public BivariateCalculator() {
        this.loaded = false;
        this.computed = false;
    }

    /*
     * compute
     * computes various monovariate statistics
     * returns true if successful, false if not
     */
    public boolean compute() {

        this.computed = false; //reset computed flag

        if (!this.loaded) {
            return false;
        }

        try {
            computeSampleSize();
            computeSum();
            computeMean();
            computeMedian();
            computeMode();
            computeMax();
            computeMin();
            computeRange();
            computeGeometricMean();
            computeSkewness();
            computeKurtosis();
            computeExcessKurtosis();
            computeVariance();
            computeStddev();
            computeQuartiles();
            computeInterquartilerange();
            computeFrequencydist();
            computePearsonCorrelation();
            computeTTest();
        } catch (Exception e) {
            return false;
        }

        this.computed = true;   //set computed flag
        return true;
    }

    /*
     * computeSampleSize
     * computes the size of the sample
     */
    protected void computeSampleSize() {
        this.sampleOne_samplesize = this.sampleOne.length;
        this.sampleTwo_samplesize = this.sampleTwo.length;
    }

    /*
     * computeSum
     * computes the total of the sample
     */
    protected void computeSum() {
        double tempOne = 0;
        double tempTwo = 0;

        /* total first sample */
        for (int i = 0; i < this.sampleOne.length; i++) {
            tempOne += this.sampleOne[i];
        }

        /* total second sample */
        for (int i = 0; i < this.sampleTwo.length; i++) {
            tempTwo += this.sampleTwo[i];
        }

        /* assign values */
        this.sampleOne_sum = tempOne;
        this.sampleTwo_sum = tempTwo;
    }

    /*
     * computeMean
     * computes the mean of the sample
     */
    protected void computeMean() {
        double tempOne = 0;
        double tempTwo = 0;

        /* total first sample */
        for (int i = 0; i < this.sampleOne.length; i++) {
            tempOne += this.sampleOne[i];
        }

        /* total second sample */
        for (int i = 0; i < this.sampleTwo.length; i++) {
            tempTwo += this.sampleTwo[i];
        }

        /* assign average */
        this.sampleOne_mean = tempOne / this.sampleOne.length;
        this.sampleTwo_mean = tempTwo / this.sampleTwo.length;
    }

    /*
     * computeMedian
     * computes the median of the sample
     */
    protected void computeMedian() {
        double tempMedianOne = 0;
        double tempMedianTwo = 0;

        /* copy samples to temporary arrays and sort*/
        double[] tempArrayOne = Arrays.copyOf(this.sampleOne, this.sampleOne.length);
        double[] tempArrayTwo = Arrays.copyOf(this.sampleTwo, this.sampleTwo.length);
        Arrays.sort(tempArrayOne);
        Arrays.sort(tempArrayTwo);

        /* find middle element of first sample */
        if (tempArrayOne.length % 2 == 0) {
            int mid1 = tempArrayOne.length / 2;
            int mid2 = (tempArrayOne.length / 2) - 1;
            tempMedianOne = (tempArrayOne[mid1] + tempArrayOne[mid2]) / 2; //takes two mid points and averages them
        } else if ((tempArrayOne.length % 2 != 0) && tempArrayOne.length > 2) {
            tempMedianOne = tempArrayOne[(int) tempArrayOne.length / 2];
        }

        /* find middle element of second sample */
        if (tempArrayTwo.length % 2 == 0) {
            int mid1 = tempArrayTwo.length / 2;
            int mid2 = (tempArrayTwo.length / 2) - 1;
            tempMedianTwo = (tempArrayTwo[mid1] + tempArrayTwo[mid2]) / 2; //takes two mid points and averages them
        } else if ((tempArrayTwo.length % 2 != 0) && tempArrayTwo.length > 2) {
            tempMedianTwo = tempArrayTwo[(int) tempArrayTwo.length / 2];
        }

        /* assign values */
        this.sampleOne_median = tempMedianOne;
        this.sampleTwo_median = tempMedianTwo;
    }

    /*
     * computeMode
     * computes the mode(s) of the sample
     */
    protected void computeMode() {
        TreeSet<Double> modesTreeSetOne = new TreeSet<Double>();
        TreeSet<Double> modesTreeSetTwo = new TreeSet<Double>();

        /* Add elements to TreeSetOne */
        int maxCountOne = 0;
        for (int i = 0; i < this.sampleOne.length; ++i) {
            int count = 0;
            for (int j = 0; j < this.sampleOne.length; ++j) {
                if (this.sampleOne[j] == this.sampleOne[i]) {
                    ++count;
                }
            }
            if (count > maxCountOne) {
                maxCountOne = count;
                modesTreeSetOne.clear();
                modesTreeSetOne.add(this.sampleOne[i]);
            } else if (count == maxCountOne) {
                modesTreeSetOne.add(this.sampleOne[i]);
            }
        }

        /* Add elements to TreeSetTwo */
        int maxCountTwo = 0;
        for (int i = 0; i < this.sampleTwo.length; ++i) {
            int count = 0;
            for (int j = 0; j < this.sampleTwo.length; ++j) {
                if (this.sampleTwo[j] == this.sampleTwo[i]) {
                    ++count;
                }
            }
            if (count > maxCountTwo) {
                maxCountTwo = count;
                modesTreeSetTwo.clear();
                modesTreeSetTwo.add(this.sampleTwo[i]);
            } else if (count == maxCountTwo) {
                modesTreeSetTwo.add(this.sampleTwo[i]);
            }
        }

        /* Add elements to string */
        this.sampleOne_mode = modesTreeSetOne.toString();
        this.sampleTwo_mode = modesTreeSetTwo.toString();
    }

    /*
     * computeMax
     * computes the greatest element of the sample
     */
    protected void computeMax() {
        double tempMaxOne = this.sampleOne[0];
        double tempMaxTwo = this.sampleTwo[0];

        /* find max of first sample */
        for (int i = 0; i < sampleOne.length; i++) {
            if (sampleOne[i] > tempMaxOne) {
                tempMaxOne = sampleOne[i];
            }
        }

        /* find max of second sample */
        for (int i = 0; i < sampleTwo.length; i++) {
            if (sampleTwo[i] > tempMaxTwo) {
                tempMaxTwo = sampleTwo[i];
            }
        }

        /* assign values */
        this.sampleOne_max = tempMaxOne;
        this.sampleTwo_max = tempMaxTwo;
    }

    /*
     * computeMin
     * computes the smallest element of the sample
     */
    protected void computeMin() {
        double tempMinOne = sampleOne[0];
        double tempMinTwo = sampleTwo[0];

        /* find min of first sample */
        for (int i = 0; i < sampleOne.length; i++) {
            if (sampleOne[i] < tempMinOne) {
                tempMinOne = sampleOne[i];
            }
        }

        /* find min of second sample */
        for (int i = 0; i < sampleTwo.length; i++) {
            if (sampleTwo[i] < tempMinTwo) {
                tempMinTwo = sampleTwo[i];
            }
        }

        /* assign values */
        this.sampleOne_min = tempMinOne;
        this.sampleTwo_min = tempMinTwo;
    }

    /*
     * computeRange
     * computes the difference betten the min and max element of the samples
     */
    protected void computeRange() {
        this.sampleOne_range = Math.abs(this.sampleOne_max - this.sampleOne_min);
        this.sampleTwo_range = Math.abs(this.sampleTwo_max - this.sampleTwo_min);
    }

    /*
     * computeGeometricMean
     * computes the geometric mean of the sample
     */
    protected void computeGeometricMean() {
        double tempsumOne = 1;
        double tempsumTwo = 1;

        /* sums the multiples of sample one */
        for (int i = 0; i < this.sampleOne.length; i++) {
            tempsumOne *= this.sampleOne[i];
        }

        /* sums the multiples of sample two */
        for (int i = 0; i < this.sampleTwo.length; i++) {
            tempsumTwo *= this.sampleTwo[i];
        }

        /* assigns values */
        this.sampleOne_geometricmean = Math.pow(tempsumOne, 1.0 / this.sampleOne.length);
        this.sampleTwo_geometricmean = Math.pow(tempsumTwo, 1.0 / this.sampleTwo.length);
    }

    /*
     * computeSkewness
     * computes the skewness of the sample
     */
    protected void computeSkewness() {

        /* computes skewness for sample one */
        double numeratorOne = 0;
        double denominatorOne = 0;

        for (int i = 0; i < this.sampleOne.length; i++) {
            numeratorOne += Math.pow(this.sampleOne[i] - this.sampleOne_mean, 3); // deviations to the third power
            denominatorOne += Math.pow(this.sampleOne[i] - this.sampleOne_mean, 2); // deviations to the second power
        }

        numeratorOne = (1.0 / this.sampleOne.length) * numeratorOne; // multiply by 1/ data size

        denominatorOne = Math.pow(denominatorOne * (1.0 / this.sampleOne.length), 3.0 / 2.0); // multiply by 1/data size and raise to the power of 1.5

        this.sampleOne_skewness = (numeratorOne / denominatorOne);

        /* computes skeness for sample two */
        double numeratorTwo = 0;
        double denominatorTwo = 0;

        for (int i = 0; i < this.sampleTwo.length; i++) {
            numeratorTwo += Math.pow(this.sampleTwo[i] - this.sampleTwo_mean, 3); // deviations to the third power
            denominatorTwo += Math.pow(this.sampleTwo[i] - this.sampleTwo_mean, 2); // deviations to the second power
        }

        numeratorTwo = (1.0 / this.sampleTwo.length) * numeratorTwo; // multiply by 1/ data size

        denominatorTwo = Math.pow(denominatorTwo * (1.0 / this.sampleTwo.length), 3.0 / 2.0); // multiply by 1/data size and raise to the power of 1.5

        this.sampleTwo_skewness = (numeratorTwo / denominatorTwo);

    }

    /*
     * computeKurtosis
     * computes the skewness of the sample
     */
    protected void computeKurtosis() {

        /* computes kurtosis of sample one */
        double numeratorOne = 0;
        double denominatorOne = 0;

        for (int i = 0; i < this.sampleOne.length; i++) {
            numeratorOne += Math.pow(this.sampleOne[i] - sampleOne_mean, 4); // deviation to the fourth power
            denominatorOne += Math.pow(this.sampleOne[i] - sampleOne_mean, 2); // deviations to the second power
        }

        numeratorOne = (double) (1.0 / this.sampleOne.length) * numeratorOne; // multiple by 1/data length

        denominatorOne = Math.pow(denominatorOne * (double) (1.0 / this.sampleOne.length), 2); // multiply by 1/data length and square

        this.sampleOne_kurtosis = (numeratorOne / denominatorOne);

        /* compute kurtosis of sample two */
        double numeratorTwo = 0;
        double denominatorTwo = 0;

        for (int i = 0; i < this.sampleTwo.length; i++) {
            numeratorTwo += Math.pow(this.sampleTwo[i] - sampleTwo_mean, 4); // deviation to the fourth power
            denominatorTwo += Math.pow(this.sampleTwo[i] - sampleTwo_mean, 2); // deviations to the second power
        }

        numeratorTwo = (double) (1.0 / this.sampleTwo.length) * numeratorTwo; // multiple by 1/data length

        denominatorTwo = Math.pow(denominatorTwo * (double) (1.0 / this.sampleTwo.length), 2); // multiply by 1/data length and square

        this.sampleTwo_kurtosis = (numeratorTwo / denominatorTwo);
    }

    /*
     * computeExcessKurtosis
     * computes the skewness of the sample
     */
    protected void computeExcessKurtosis() {
        this.sampleOne_excesskurtosis = this.sampleOne_kurtosis - 3;
        this.sampleTwo_excesskurtosis = this.sampleTwo_kurtosis - 3;

    }

    /*
     * computeVariance
     * computes the difference betten the min and max element of the sample
     */
    protected void computeVariance() {

        /* computes variance of sample one */
        double tempVarianceOne = 0;

        for (int i = 0; i < this.sampleOne.length; i++) {
            tempVarianceOne += (this.sampleOne_mean - this.sampleOne[i]) * (this.sampleOne_mean - this.sampleOne[i]);
        }
        this.sampleOne_variance = tempVarianceOne / this.sampleOne.length;

        /* computes variance of sample two */
        double tempVarianceTwo = 0;

        for (int i = 0; i < this.sampleTwo.length; i++) {
            tempVarianceTwo += (this.sampleTwo_mean - this.sampleTwo[i]) * (this.sampleTwo_mean - this.sampleTwo[i]);
        }
        this.sampleTwo_variance = tempVarianceTwo / this.sampleTwo.length;

    }

    /*
     * computeStddev
     * computes the standard deviation of the elements of the sample
     */
    protected void computeStddev() {

        /* computes standard deviation of sample one */
        double tempStddevOne = 0;

        for (int i = 0; i < this.sampleOne.length; i++) {
            tempStddevOne += Math.pow((this.sampleOne[i] - this.sampleOne_mean), 2);
        }

        this.sampleOne_stddev = Math.sqrt((tempStddevOne / (this.sampleOne.length - 1)));

        /* computes the standard deviation of sample two */
        double tempStddevTwo = 0;

        for (int i = 0; i < this.sampleTwo.length; i++) {
            tempStddevTwo += Math.pow((this.sampleTwo[i] - this.sampleTwo_mean), 2);
        }

        this.sampleTwo_stddev = Math.sqrt((tempStddevTwo / (this.sampleTwo.length - 1)));
    }

    /*
     * computeQuartiles
     * computes the four quartile values cutoff of the sample
     */
    protected void computeQuartiles() {
        /* copy samples to temporary arrays and sort*/
        double[] tempArrayOne = Arrays.copyOf(this.sampleOne, this.sampleOne.length);
        double[] tempArrayTwo = Arrays.copyOf(this.sampleTwo, this.sampleTwo.length);
        Arrays.sort(tempArrayOne);
        Arrays.sort(tempArrayTwo);

        /* assign values of sample one quartiles */
        this.sampleOne_firstquartile = tempArrayOne[(int) Math.floor(0.25 * (double) tempArrayOne.length)];
        this.sampleOne_secondquartile = tempArrayOne[(int) Math.floor(0.50 * (double) tempArrayOne.length)];
        this.sampleOne_thirdquartile = tempArrayOne[(int) Math.floor(0.75 * (double) tempArrayOne.length)];
        this.sampleOne_fourthquartile = tempArrayOne[tempArrayOne.length - 1];

        /* assign values of sample two quartiles */
        this.sampleTwo_firstquartile = tempArrayTwo[(int) Math.floor(0.25 * (double) tempArrayTwo.length)];
        this.sampleTwo_secondquartile = tempArrayTwo[(int) Math.floor(0.50 * (double) tempArrayTwo.length)];
        this.sampleTwo_thirdquartile = tempArrayTwo[(int) Math.floor(0.75 * (double) tempArrayTwo.length)];
        this.sampleTwo_fourthquartile = tempArrayTwo[tempArrayTwo.length - 1];

    }

    /*
     * computeInterquartilerange
     * computes the four quartile values cutoff of the sample
     */
    protected void computeInterquartilerange() {
        this.sampleOne_firstinterquartilerange = this.sampleOne_firstquartile - this.sampleOne_min;
        this.sampleOne_secondinterquartilerange = this.sampleOne_secondquartile - this.sampleOne_firstquartile;
        this.sampleOne_thirdinterquartilerange = this.sampleOne_thirdquartile - this.sampleOne_secondquartile;
        this.sampleOne_fourthinterquartilerange = this.sampleOne_fourthquartile - this.sampleOne_thirdquartile;

        this.sampleTwo_firstinterquartilerange = this.sampleTwo_firstquartile - this.sampleTwo_min;
        this.sampleTwo_secondinterquartilerange = this.sampleTwo_secondquartile - this.sampleTwo_firstquartile;
        this.sampleTwo_thirdinterquartilerange = this.sampleTwo_thirdquartile - this.sampleTwo_secondquartile;
        this.sampleTwo_fourthinterquartilerange = this.sampleTwo_fourthquartile - this.sampleTwo_thirdquartile;

    }

    /*
     * computeFrequencydist
     * computes the frequency distribution of the sample
     */
    protected void computeFrequencydist() {
        /* copy samples to temporary arrays and sort*/
        double[] tempArrayOne = Arrays.copyOf(this.sampleOne, this.sampleOne.length);
        double[] tempArrayTwo = Arrays.copyOf(this.sampleTwo, this.sampleTwo.length);
        Arrays.sort(tempArrayOne);
        Arrays.sort(tempArrayTwo);

        /* compute the frequency distribution of the first sample */
        StringBuilder sbOne = new StringBuilder();
        
        //this is only for JUnit testing
        freqCount = new ArrayList<Integer>();
        freqCount3 = new ArrayList<Integer>();

        for (int i = 0; i < tempArrayOne.length; i++) {
            int count = 1;
            sbOne.append("     ");
            String tempOne = Double.toString(tempArrayOne[i]);
            while ((i < tempArrayOne.length - 1)
                    && (tempArrayOne[i] == tempArrayOne[i + 1])) {
                count++;
                i++;
            }

            sbOne.append(count);
            sbOne.append("\t\t");
            sbOne.append(tempOne);
            sbOne.append("\n");
            
            freqCount.add(count); //for JUnit only
        }
        this.sampleOne_frequencydist = sbOne.toString();

        /* compute the frequency distribution of the second sample */
        StringBuilder sbTwo = new StringBuilder();

        for (int i = 0; i < tempArrayTwo.length; i++) {
            int count = 1;
            sbTwo.append("     ");
            String tempTwo = Double.toString(tempArrayTwo[i]);
            while ((i < tempArrayTwo.length - 1)
                    && (tempArrayTwo[i] == tempArrayTwo[i + 1])) {
                count++;
                i++;
            }
            sbTwo.append(count);
            sbTwo.append("\t\t");
            sbTwo.append(tempTwo);
            sbTwo.append("\n");
            
            freqCount3.add(count); //for JUnit only
        }
        this.sampleTwo_frequencydist = sbTwo.toString();
        
        //used for JUnit testing only
        freqCount2 = new int[freqCount.size()];
        for (int j = 0; j < freqCount.size(); j++) {
        	freqCount2[j] = freqCount.get(j);
        }
        freqCount4 = new int[freqCount3.size()];
        for (int j = 0; j < freqCount.size(); j++) {
        	freqCount4[j] = freqCount3.get(j);
        }
    }
    
    /*
     * computePearsonCorrelation
     * computes the pearson correlation of the two samples
     * where x = sample one, y = sample two
     * 
     *                    n[sigma(xy)]-[sigma(x)][sigma(y)]
     * r =    ----------------------------------------------------------
     *        sqrt([n*sigma(x^2) - sigma(x)^2][n*sigma(y^2) - sigma(y)^2]
     * 
     */
    protected void computePearsonCorrelation() {
        double n = 0;
        double sigma_xy = 0;
        double sigma_x = 0;
        double sigma_y = 0;
        double sigma_x2 = 0;
        double sigma_y2 = 0;
        double numerator = 0;
        double denominator = 0;
        double result = 0;
        
        /* compute n */
        n = this.sampleOne.length;
        
        /* compute sigma xy */
        for(int i = 0; i < n; i++){
            sigma_xy += this.sampleOne[i]*this.sampleTwo[i];
        }
        
        /* compute sigma x */
        for(int i = 0; i < n; i++){
            sigma_x += this.sampleOne[i];
        }
        
        /* compute sigma y */
        for(int i = 0; i < n; i++){
            sigma_y += this.sampleTwo[i];
        }
        
        /* compute sigma(x^2) */
        for(int i = 0; i < n; i++){
            sigma_x2 += this.sampleOne[i]*this.sampleOne[i];
        }
        
        /* compute sigma(y^2) */
        for(int i = 0; i < n; i++){
            sigma_y2 += this.sampleTwo[i]*this.sampleTwo[i];
        }
        
        numerator = (n*sigma_xy)-(sigma_x*sigma_y);
        denominator = Math.sqrt(((n*sigma_x2)-Math.pow(sigma_x, 2))*((n*sigma_y2)-Math.pow(sigma_y, 2)));
        result = numerator / denominator;
        this.pearsoncorrelation = result;        
    }

    /*
     * computeTTest
     * computes a t-test against the two samples
     * where x is sample one, y is sample two,
     * n1 is the size of sample one, & n2 is the size of sample two
     * 
     *                   mean(x) - mean(y)
     * t =    -----------------------------------------
     *          sqrt(variance(x)/n1 + variance(y)/n2)
     * 
     */
    protected void computeTTest() {
        double numerator = 0;
        double denominator = 0;
        double result = 0;
        
        numerator = (this.sampleOne_mean - this.sampleTwo_mean);
        denominator = Math.sqrt(
                ((this.sampleOne_variance + this.sampleTwo_variance) /
                (this.sampleOne_samplesize/this.sampleTwo_samplesize)) *
                (1/this.sampleOne_samplesize + 1/this.sampleTwo_samplesize));
        result = numerator / denominator;
        this.ttest = result;
    }    
    

    /*
     * getSampleSizeOne
     * returns the current sample size of sample one
     */
    public int getSampleSizeOne() {
        return this.sampleOne_samplesize;
    }

    /*
     * getSampleSizeTwo
     * returns the current sample size of sample two
     */
    public int getSampleSizeTwo() {
        return this.sampleTwo_samplesize;
    }

    /*
     * getSumOne
     * returns the sum of the sample one
     */
    public double getSumOne() {
        return this.sampleOne_sum;
    }

    /*
     * getSumTwo
     * returns the sum of the sample two
     */
    public double getSumTwo() {
        return this.sampleTwo_sum;
    }

    /*
     * getMeanOne
     * returns the mean of the sample one
     */
    public double getMeanOne() {
        return this.sampleOne_mean;
    }

    /*
     * getMeanTwo
     * returns the mean of the sample two
     */
    public double getMeanTwo() {
        return this.sampleTwo_mean;
    }

    /*
     * getMedianOne
     * returns the median of the sample one
     */
    public double getMedianOne() {
        return this.sampleOne_median;
    }

    /*
     * getMedianTwo
     * returns the median of the sample two
     */
    public double getMedianTwo() {
        return this.sampleTwo_median;
    }

    /*
     * getModeOne
     * returns the mode(s) of the sample one
     */
    public String getModeOne() {
        return this.sampleOne_mode;
    }

    /*
     * getModeTwo
     * returns the mode(s) of the sample two
     */
    public String getModeTwo() {
        return this.sampleTwo_mode;
    }

    /*
     * getMaxOne
     * returns the greatest valued element of the sample one
     */
    public double getMaxOne() {
        return this.sampleOne_max;
    }

    /*
     * getMaxTwo
     * returns the greatest valued element of the sample two
     */
    public double getMaxTwo() {
        return this.sampleTwo_max;
    }

    /*
     * getMinOne
     * returns the smallest valued element of the sample one 
     */
    public double getMinOne() {
        return this.sampleOne_min;
    }

    /*
     * getMinTwo
     * returns the smallest valued element of the sample two 
     */
    public double getMinTwo() {
        return this.sampleTwo_min;
    }

    /*
     * getRangeOne
     * returns the difference between the max and min elements
     */
    public double getRangeOne() {
        return this.sampleOne_range;
    }

    /*
     * getRangeTwo
     * returns the difference between the max and min elements
     */
    public double getRangeTwo() {
        return this.sampleTwo_range;
    }

    /*
     * getSkewnessOne
     * returns the difference between the max and min elements
     */
    public double getSkewnessOne() {
        return this.sampleOne_skewness;
    }

    /*
     * getSkewnessTwo
     * returns the difference between the max and min elements
     */
    public double getSkewnessTwo() {
        return this.sampleTwo_skewness;
    }

    /*
     * getKurtosisOne
     * returns the kurtosis of the sample
     */
    public double getKurtosisOne() {
        return this.sampleOne_kurtosis;
    }

    /*
     * getKurtosisTwo
     * returns the kurtosis of the sample
     */
    public double getKurtosisTwo() {
        return this.sampleTwo_kurtosis;
    }

    /*
     * getExceessKurtosisOne
     * returns the kurtosis of the sample
     */
    public double getExcessKurtosisOne() {
        return this.sampleOne_excesskurtosis;
    }

    /*
     * getExceessKurtosisTwo
     * returns the kurtosis of the sample
     */
    public double getExcessKurtosisTwo() {
        return this.sampleTwo_excesskurtosis;
    }

    /*
     * getGeometricMeanOne
     * returns the geometric mean of the sample
     */
    public double getGeometricMeanOne() {
        return this.sampleOne_geometricmean;
    }

    /*
     * getGeometricMeanTwo
     * returns the geometric mean of the sample
     */
    public double getGeometricMeanTwo() {
        return this.sampleTwo_geometricmean;
    }

    /*
     * getVarianceOne
     * returns the variance of the sample
     */
    public double getVarianceOne() {
        return this.sampleOne_variance;
    }

    /*
     * getVarianceTwo
     * returns the variance of the sample
     */
    public double getVarianceTwo() {
        return this.sampleTwo_variance;
    }


    /*
     * getStddevOne
     * returns the standard deviation of the sample
     */
    public double getStddevOne() {
        return this.sampleOne_stddev;
    }

    /*
     * getStddevTwo
     * returns the standard deviation of the sample
     */
    public double getStddevTwo() {
        return this.sampleTwo_stddev;
    }

    /*
     * getFirstQuartileOne
     * returns the first quartile values cutoff of the sample   
     */
    public double getFirstQuartileOne() {
        return this.sampleOne_firstquartile;
    }

    /*
     * getFirstQuartileTwo
     * returns the first quartile values cutoff of the sample   
     */
    public double getFirstQuartileTwo() {
        return this.sampleTwo_firstquartile;
    }

    /*
     * getSecondQuartileOne
     * returns the second quartile values cutoff of the sample   
     */
    public double getSecondQuartileOne() {
        return this.sampleOne_secondquartile;
    }

    /*
     * getSecondQuartileTwo
     * returns the second quartile values cutoff of the sample   
     */
    public double getSecondQuartileTwo() {
        return this.sampleTwo_secondquartile;
    }

    /*
     * getThirdQuartileOne
     * returns the third quartile values cutoff of the sample   
     */
    public double getThirdQuartileOne() {
        return this.sampleOne_thirdquartile;
    }

    /*
     * getThirdQuartileTwo
     * returns the third quartile values cutoff of the sample   
     */
    public double getThirdQuartileTwo() {
        return this.sampleTwo_thirdquartile;
    }

    /*
     * getForthQuartileOne
     * returns the fourth quartile values cutoff of the sample   
     */
    public double getForthQuartileOne() {
        return this.sampleOne_fourthquartile;
    }

    /*
     * getForthQuartileTwo
     * returns the fourth quartile values cutoff of the sample   
     */
    public double getForthQuartileTwo() {
        return this.sampleTwo_fourthquartile;
    }

    /*
     * getFirstInterquartilerangeOne
     * retuns the first interquartile range of the sample
     */
    public double getFirstInterquartileRangeOne() {
        return this.sampleOne_firstinterquartilerange;
    }

    /*
     * getFirstInterquartilerangeTwo
     * retuns the first interquartile range of the sample
     */
    public double getFirstInterquartileRangeTwo() {
        return this.sampleTwo_firstinterquartilerange;
    }

    /*
     * getSecondInterquartilerangeOne
     * retuns the second interquartile range of the sample
     */
    public double getSecondInterquartileRangeOne() {
        return this.sampleOne_secondinterquartilerange;
    }

    /*
     * getSecondInterquartilerangeTwo
     * retuns the second interquartile range of the sample
     */
    public double getSecondInterquartileRangeTwo() {
        return this.sampleTwo_secondinterquartilerange;
    }

    /*
     * getThirdInterquartilerangeOne
     * retuns the third interquartile range of the sample
     */
    public double getThirdInterquartileRangeOne() {
        return this.sampleOne_thirdinterquartilerange;
    }

    /*
     * getThirdInterquartilerangeTwo
     * retuns the third interquartile range of the sample
     */
    public double getThirdInterquartileRangeTwo() {
        return this.sampleTwo_thirdinterquartilerange;
    }

    /*
     * getFourthInterquartilerangeOne
     * retuns the fourth interquartile range of the sample
     */
    public double getFourthInterquartileRangeOne() {
        return this.sampleOne_fourthinterquartilerange;
    }

    /*
     * getFourthInterquartilerangeTwo
     * retuns the fourth interquartile range of the sample
     */
    public double getFourthInterquartileRangeTwo() {
        return this.sampleTwo_fourthinterquartilerange;
    }

    /*
     * getFrequencydistOne
     * returns the frequency distribution of the sample
     */
    public String getFrequencydistOne() {
        return this.sampleOne_frequencydist;
    }

    /*
     * getFrequencydistTwo
     * returns the frequency distribution of the sample
     */
    public String getFrequencydistTwo() {
        return this.sampleTwo_frequencydist;
    }
    
    /*
     * getPearsonCorrelation
     * returns the pearson correlation of the two samples
     */
    public double getPearsonCorrelation() {
        return this.pearsoncorrelation;
    }
    
    /*
     * getTTest
     * returns the t-test score between the two samples
     */
    public double getTTest() {
        return this.ttest;
    }

    /*
     * load
     * loads new file at given filepath argument
     * returns true if successful, false if not
     */
    public boolean load(double[] sampleOne, double[] sampleTwo) {
        /* reset loaded flag */
        this.loaded = false;

        /* create new array from provided sample */
        try {
            this.sampleOne = sampleOne;
            this.sampleTwo = sampleTwo;
        } catch (Exception e) {
            return false;
        }

        /* set loaded flag and return success */
        this.loaded = true;
        return true;
    }

    /*
     * toString
     * returns a prinout of the monovariate statistics of the sample
     */
    public String toString() {

        if (!this.computed) {
            String errormsg = "Could not compute input";
            return errormsg;
        }

        StringBuilder sb = new StringBuilder("");

        String printoutOne = ""
                + "Sample Size:\t\t" + this.sampleOne_samplesize + "\n"
                + "Sum:\t\t" + this.sampleOne_sum + "\n"
                + "Mean:\t\t" + this.sampleOne_mean + "\n"
                + "Median:\t\t" + this.sampleOne_median + "\n"
                + "Mode(s):\t\t" + this.sampleOne_mode + "\n"
                + "Max:\t\t" + this.sampleOne_max + "\n"
                + "Min:\t\t" + this.sampleOne_min + "\n"
                + "Range:\t\t" + this.sampleOne_range + "\n"
                + "Geom. Mean:\t\t" + this.sampleOne_geometricmean + "\n"
                + "Skewness:\t\t" + this.sampleOne_skewness + "\n"
                + "Kurtosis:\t\t" + this.sampleOne_kurtosis + "\n"
                + "Excess Kurtosis:\t" + this.sampleOne_excesskurtosis + "\n"
                + "Variance:\t\t" + this.sampleOne_variance + "\n"
                + "Std Deviation:\t\t" + this.sampleOne_stddev + "\n"
                + "Quartiles:\n"
                + "     " + "1st:\t\t" + this.sampleOne_firstquartile + "\n"
                + "     " + "2nd:\t\t" + this.sampleOne_secondquartile + "\n"
                + "     " + "3rd:\t\t" + this.sampleOne_thirdquartile + "\n"
                + "     " + "4th:\t\t" + this.sampleOne_fourthquartile + "\n"
                + "Interquartile Range:\n"
                + "     " + "0-1:\t\t" + this.sampleOne_firstinterquartilerange + "\n"
                + "     " + "1-2:\t\t" + this.sampleOne_secondinterquartilerange + "\n"
                + "     " + "2-3:\t\t" + this.sampleOne_thirdinterquartilerange + "\n"
                + "     " + "3-4:\t\t" + this.sampleOne_fourthinterquartilerange + "\n"
                + "Frequency Distribution:\n"
                + this.sampleOne_frequencydist;

        String printoutTwo = ""
                + "Sample Size:\t\t" + this.sampleTwo_samplesize + "\n"
                + "Sum:\t\t" + this.sampleTwo_sum + "\n"
                + "Mean:\t\t" + this.sampleTwo_mean + "\n"
                + "Median:\t\t" + this.sampleTwo_median + "\n"
                + "Mode(s):\t\t" + this.sampleTwo_mode + "\n"
                + "Max:\t\t" + this.sampleTwo_max + "\n"
                + "Min:\t\t" + this.sampleTwo_min + "\n"
                + "Range:\t\t" + this.sampleTwo_range + "\n"
                + "Geom. Mean:\t\t" + this.sampleTwo_geometricmean + "\n"
                + "Skewness:\t\t" + this.sampleTwo_skewness + "\n"
                + "Kurtosis:\t\t" + this.sampleTwo_kurtosis + "\n"
                + "Excess Kurtosis:\t" + this.sampleTwo_excesskurtosis + "\n"
                + "Variance:\t\t" + this.sampleTwo_variance + "\n"
                + "Std Deviation:\t\t" + this.sampleTwo_stddev + "\n"
                + "Quartiles:\n"
                + "     " + "1st:\t\t" + this.sampleTwo_firstquartile + "\n"
                + "     " + "2nd:\t\t" + this.sampleTwo_secondquartile + "\n"
                + "     " + "3rd:\t\t" + this.sampleTwo_thirdquartile + "\n"
                + "     " + "4th:\t\t" + this.sampleTwo_fourthquartile + "\n"
                + "Interquartile Range:\n"
                + "     " + "0-1:\t\t" + this.sampleTwo_firstinterquartilerange + "\n"
                + "     " + "1-2:\t\t" + this.sampleTwo_secondinterquartilerange + "\n"
                + "     " + "2-3:\t\t" + this.sampleTwo_thirdinterquartilerange + "\n"
                + "     " + "3-4:\t\t" + this.sampleTwo_fourthinterquartilerange + "\n"
                + "Frequency Distribution:\n"
                + this.sampleTwo_frequencydist;
        String printoutBivariate = ""
                + "Pearson's Correlation:\t" +this.pearsoncorrelation + "\n"
                + "T-Test score: \t\t" + this.ttest + "\n";

        sb.append("[MONOVARIATE ANALYSIS - SAMPLE 1]\n");
        sb.append(printoutOne);
        sb.append("\n");
        sb.append("[MONOVARIATE ANALYSIS - SAMPLE 2]\n");
        sb.append(printoutTwo);
        sb.append("\n");
        sb.append("[BIVARIATE ANALYSIS]");
        sb.append("\n");
        sb.append(printoutBivariate);
        

        return sb.toString();
    }
}